#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>

/* #include "softfloat.h" */
#include "softfloat.c"		/* this file contain some static function which may be difficult to deal */


float32 gen_random_float32()
{
  flag sign;
  int_fast16_t exp;
  uint32_t sig;

  /* sign = rand() & 1; */
  /* exp = rand() & 0xff; */
  /* sig = rand() & 0x7fffff; */

  sign = 1;
  exp = 127+31;			/* -2^31 */
  sig = 1;

   return packFloat32( sign, exp, sig );
  /* return ( ( ( (uint32_t) sign )<<31 ) + ( ( (uint32_t) exp )<<23 ) + sig); */
}

float64 gen_random_float64()
{
  flag sign;
  int16_t exp;
  uint64_t sig;

  sign = rand() & 1;
  exp = rand() & 0x7ff;

  sig = rand();
  sig = (sig<<32) | rand();
  sig &= (1LL<<52)-1;


  /* sign = 1; */
  /* exp = 1023+31;			/\* -2^31 *\/ */
  /* sig = 0; */

  return ( ( ( (uint64_t) sign )<<63 ) + ( ( (uint64_t) exp )<<52 ) + sig);
}  


float gen_random_float()
{
  flag sign;
  int16_t exp;
  uint32_t sig;
  uint32_t res;

  sign = rand() & 1;
  exp = rand() & 0xff;
  sig = rand() & 0x7fffff;

  //  return packFloat32( sign, exp, sig );
  res = ( ( ( (uint32_t) sign )<<31 ) + ( ( (uint32_t) exp )<<23 ) + sig);
  return *((float *)&res);
}


double gen_random_double()
{
  flag sign;
  int_fast16_t exp;
  uint64_t sig;
  uint64_t res;

  sign = rand() & 1;
  exp = rand() & 0xff;

  sig = rand();
  sig = (sig<<32) | rand();
  sig &= (1LL<<52)-1;

  res = ( ( ( (uint64_t) sign )<<63 ) + ( ( (uint64_t) exp )<<52 ) + sig);
  return (*((double *)&res));
}  


void float32_to_str(float32 a, char *str)
{
  float f = *((float *)&a);
  sprintf(str, "%f", f);
}



#define FLOAT(a) (*((float *)&a))
#define DOUBLE(a) (*((double *)&a))
#define SOFTFLOAT32(a) (*((float32 *)(&a)))
#define SOFTFLOAT64(a) (*((float64 *)(&a)))


// ==================================================
int main()
{

  float32 a, b, c;
  float fa, fb, fc;
  float32 res1, res2;

  fa = 3.14;
  fb = 12345.6789;
  
  /* res2 = float32_add(float32_mul(SOFTFLOAT32(fa),SOFTFLOAT32(fb)), SOFTFLOAT32(fc)); */
  res1 = float32_mul(SOFTFLOAT32(fa),SOFTFLOAT32(fb));

  printf("%f * %f => %f (correct:%f)\n", fa, fb, *((float *)&res1), fa*fb);
  
  /* printf("It works!\n"); */


  
/*   //int32_t */
/*   int i, j, k; */
/*   //float a = -1229374295729357213957234.001; */
/*   float a = -2147483648.0; */

/*   set_config(1,			/\* has2008 *\/ */
/*   	     1,			/\* abs2008 *\/ */
/*   	     1,			/\* nan2008 *\/ */
/*   	     0,			/\* mac2008, fused FMA or not *\/ */
/*   	     0,			/\* flush_to_zero *\/ */
/*   	     float_round_nearest_even, /\* rounding mode *\/ */
/*   	     0x00		  /\* exp_enable *\/ */
/*   	     ); */

/*   /\* set_config(0,			/\\* has2008 *\\/ *\/ */
/*   /\* 	     0,			/\\* abs2008 *\\/ *\/ */
/*   /\* 	     0,			/\\* nan2008 *\\/ *\/ */
/*   /\* 	     0,			/\\* mac2008 *\\/ *\/ */
/*   /\* 	     0,			/\\* flush_to_zero *\\/ *\/ */
/*   /\* 	     float_round_nearest_even, /\\* rounding mode *\\/ *\/ */
/*   /\* 	     0x00		  /\\* exp_enable *\\/ *\/ */
/*   /\* 	     ); *\/ */


/*   /\* k = float32_to_int32_round_up( (*(unsigned int *)&a)); *\/ */
/*   /\* printf("a = %f, k = %d\n", a, k); *\/ */

/*   /\* a = -2157483648.0; *\/ */
/*   /\* k = float32_to_int32_round_up( (*(unsigned int *)&a)); *\/ */
/*   /\* printf("a = %f, k = %d\n", a, k); *\/ */


/*   /\* for(i=0;i<10000;i++) *\/ */
/*   /\* // while(1) *\/ */
/*   /\*   { *\/ */
/*   /\*     int rand = random() | 0x80000000; *\/ */
/*   /\*     float *fptr = (float *)(&rand); *\/ */
/*   /\*     int i32 = (int)(*fptr); *\/ */
/*   /\*     int cvt = float32_to_int32_round_up( rand ); *\/ */
      
/*   /\*     printf("%x, float:%f (int:%d) => int:%d\n", rand, *fptr, i32, cvt); *\/ */
/*   /\*   } *\/ */

/*   printf("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n"); */
/*   { */
/*     uint32_t u32; */
/*     char str[100]; */
    
/* /\* int16_t q15; *\/ */
/* /\* float32 f; *\/ */
/* /\* q15 = 0x8000; *\/ */
/*  /\* q15 = 0x0001; *\/ */
/* /\* f = q15_to_float32(q15); *\/ */
/* /\*     float64 f; *\/ */
    
/* /\*     int q31; *\/ */
/* /\*     q31 = 0x80000000; *\/ */
/* /\*     f = q31_to_float64(q31); *\/ */

    
    
/* /\* printf("result : %016lx\n", f); *\/ */

/*     /\* printf("%08x\n", float32_round_to_int(0x00000001)); *\/ */


    
    
/*     /\* float32_to_str(packFloat32( 1, 158, 0 ), str); *\/ */
/*     /\* printf("%s\n", str); *\/ */


/*     /\* clear_exp_flags(); *\/ */
/*     /\* float32_scalbn(1, 0); *\/ */
/*     /\* printf("exp_flags : %x\n", get_exp_flags()); *\/ */

/*   } */

/*   { */
/*     /\* for FPU *\/ */
/*     set_config(1,			/\* has2008 *\/ */
/* 	       1,			/\* abs2008 *\/ */
/* 	       1,			/\* nan2008 *\/ */
/* 	       0,			/\* mac2008, fused FMA or not *\/ */
/* 	       0,			/\* flush_to_zero *\/ */
/* 	       float_round_nearest_even, /\* rounding mode *\/ */
/* 	       0x11		  /\* exp_enable *\/ */
/*   	     ); */

    
/*     clear_exp_flags(); */
/*     //    int x = float32_to_int32_round(0xcf5c5a2b, float_round_up); */
/*     //int x = float32_to_int32_round(0xbfb4c9df, float_round_nearest_even); */
/*     /\* int64_t x = float32_to_int64_round(0x7fc00000, float_round_nearest_even); *\/ */
/*     /\* int64_t x = float32_to_int64_round(0x80000001, float_round_down); /\\* floor.l.s *\\/ *\/ */
/*     /\* float64 x = float32_to_float64(0x7f800001); /\\* cvt.d.s *\\/ *\/ */

/*     int32_t i32 = float32_to_int64_round(0x49aabfbd, float_round_down); */
    
/*     printf("result : %x\n", i32); */
/*     return 0; */
/*   } */


  
/*   /\* { *\/ */
/*   /\*   set_config(1,			/\\* has2008 *\\/ *\/ */
/*   /\* 	       1,			/\\* abs2008 *\\/ *\/ */
/*   /\* 	       1,			/\\* nan2008 *\\/ *\/ */
/*   /\* 	       0,			/\\* mac2008, fused FMA or not *\\/ *\/ */
/*   /\* 	       0,			/\\* flush_to_zero *\\/ *\/ */
/*   /\* 	       float_round_nearest_even, /\\* rounding mode *\\/ *\/ */
/*   /\* 	       0x11		  /\\* exp_enable *\\/ *\/ */
/*   /\* 	     ); *\/ */

    
/*   /\*   clear_exp_flags(); *\/ */
/*   /\*   uint64_t res = float64_scalbn(LIT64(0x100fffffffffffff), -100); *\/ */
/*   /\*   printf("result : %016lx, exp_flags : %x\n", res, get_exp_flags()); *\/ */


    
    
/* return 0; */


/* //float32 f32 = float64_to_float32(LIT64(0xffffffffb2a72665)); */
/* float32 f32 = float64_to_float32(LIT64(0xffffffffffffffff)); */
/* printf("=> %08x\n", f32); */
/* return 0; */
/* } */



/*   /\* { *\/ */
/*   /\*   i32 = float32_to_int32_round(a, float_round_system); *\/ */
/*   /\*   0x9443148a66 *\/ */
/*   /\* } *\/ */

  
/*   { */
/*     double f = 1.0; */
/*     // float64 a = 0x3ff0000000000000LL; */
/*     float64 a = 0x4027f15d4e8fb00cLL; */
/*     int32_t i32; */

/*     printf("input : %f\n", *((double *)&a)); */
/*     //i32 = float64_to_int32_round(a, float_round_system); */
/*     //i32 = float64_to_int32_round(a, float_round_nearest_even); */
/*     i32 = float64_to_int32_round(a, float_round_to_zero); */

/*     printf("i32 = %x (%d)\n", i32, i32); */

/* return 0; */

    
/*   } */

  
/*   /\* //  for(i=0;i<1000;i++) *\/ */
/*   /\* { *\/ */
/*   /\*   //      int rand = random(); *\/ */
/*   /\*   //int rand = 0xffffffff; *\/ */
/*   /\*   //float *fptr = (float *)(&rand); *\/ */
/*   /\*   //int i32 = (int)(*fptr); *\/ */
/*   /\*   double df; *\/ */
/*   /\*   int32_t i32a, i32b; *\/ */
/*   /\*   float64 fr; *\/ */
    
/*   /\*   fr = gen_random_float64(); *\/ */
    
/*   /\*   printf("%f \n", float64_val(fr)); *\/ */
    
/*   /\*   df = *((double *)(&fr)); *\/ */
/*   /\*   i32a = (int32_t)df; *\/ */
/*   /\*   i32b = float64_to_int32(fr); *\/ */
/*   /\*   printf("original : %d, covert : %d\n", i32a, i32b); *\/ */
      
/*   /\* } *\/ */
  
/*   { */
/*     float a = 3.1415; */
/*     float32 res = float32_exp2(SOFTFLOAT32(a)); */
/*     printf("res = %f\n", FLOAT(res)); */
/*   } */


/*   { */
/*     uint64_t u64 = 0x12345678abcdef01; */
/*     //double d64 = 12325234.0; */
/*     //double d64 = -123.0; */
/*     // double d64 = pow(2,63) + 1234; */
/*     double d64 = (double)(unsigned long long)(1LL<<63) + 1234.0; */
/*     u64 = float64_to_uint64( *((float64 *)&d64) ); */
/*     printf("%llx \n", u64); */
/*     printf("%llu \n", u64); */
/*   } */

/*   printf("-------------------- test scaleB() --------------------\n"); */
/*   { */
/*     float64 a, res; */
/*     long long int exp; */
/*     double fa; */
/*     fa = 12.34567; */
/*     a = *((float64 *)&fa); */
/*     exp = 0x7fffffffffffffffLL; */
/*     res = float64_scaleB(a, exp); */
/*     printf("%llx\n", res); */
/*     printf("%lf ---2^%lld---> %lf\n", fa, exp, *((double *)&res)); */
    
/*   } */
/*   exit(0); */





/*   printf("-------------------- test FMA --------------------\n"); */
/*   //  goto test_FMA64; */

/*   for(i=0;i<100000;i++) */
/*   { */
/*     float32 a, b, c; */
/*     float fa, fb, fc; */
/*     float32 res1, res2; */

/*     /\* fa = 123.456; *\/ */
/*     /\* fb = 0.789; *\/ */
/*     /\* fc = 3.1415926; *\/ */

/*     fa = gen_random_float(); */
/*     fb = gen_random_float(); */
/*     fc = gen_random_float(); */

/*     //75.951607 * 1.011487 + 2.561120 = 79.385223 (fused FMA) <-> 79.385216 (unfused FMA)  => Not Equal */
/*     /\* fa = 75.951607;	//0x4297e739; *\/ */
/*     /\* fb = 1.011487;	//0x3f81786c; *\/ */
/*     /\* fc = 2.561120;	//0x4023e965; *\/ */

/*     /\* uint32_t ta, tb ,tc; *\/ */
/*     /\* ta = 0x4297e739; *\/ */
/*     /\* tb = 0x3f81786c; *\/ */
/*     /\* tc = 0x4023e965; *\/ */

/*     /\* fa = FLOAT(ta); *\/ */
/*     /\* fb = FLOAT(tb); *\/ */
/*     /\* fc = FLOAT(tc); *\/ */


    
/*     res1 = float32_muladd(SOFTFLOAT32(fa),SOFTFLOAT32(fb), SOFTFLOAT32(fc), 0); */
/*     // printf("%f * %f + %f = %f (fused FMA)  <->  ", fa, fb, fc, FLOAT(res1)); */

    
/*     res2 = float32_add(float32_mul(SOFTFLOAT32(fa),SOFTFLOAT32(fb)), SOFTFLOAT32(fc)); */
/*     // printf("%f * %f + %f = %f (unfused FMA)   => ", fa, fb, fc, FLOAT(res2)); */
/*     // printf("%f (unfused FMA)   => ", FLOAT(res2)); */
  
/*     printf("%f * %f + %f = %f (fused FMA) <-> %f (unfused FMA)  => %s\n", fa, fb, fc, FLOAT(res1), FLOAT(res2), res1==res2 ? "equal" : "not equal"); */

/*     if(res1 != res2) { */
/*       //printf("%f * %f + %f = %f (fused FMA) <-> %f (unfused FMA)  => Not Equal\n", fa, fb, fc, FLOAT(res1), FLOAT(res2)); */

/*       /\* char str1[20], str2[20]; *\/ */
/*       /\* sprintf(str1, "%f", FLOAT(res1)); *\/ */
/*       /\* sprintf(str2, "%f", FLOAT(res2)); *\/ */
/*       /\* if(strcmp(str1, str2)) *\/ */
/*       /\* 	{ *\/ */
/*       /\* 	  printf("%f * %f + %f = %f (fused FMA) <-> %f (unfused FMA)  => Not Equal\n", fa, fb, fc, FLOAT(res1), FLOAT(res2)); *\/ */
/*       /\* 	  printf("fa = %x, fb = %x, fc = %x\n", SOFTFLOAT32(fa), SOFTFLOAT32(fb), SOFTFLOAT32(fc)); *\/ */
/*       /\* 	} *\/ */
      
/*     } */
/*     /\* else *\/ */
/*     /\*   printf("equal\n"); *\/ */
    
/*   } */

/*   exit(0); */


/*  test_FMA64: */
  
/*     for(i=0;i<100000;i++) */
/*   { */
/*     //float32 a, b, c; */
/*     double fa, fb, fc; */
/*     float64 res1, res2; */
/*     int64_t ia, ib; */


/*     fa = gen_random_double(); */
/*     fb = gen_random_double(); */
/*     fc = gen_random_double(); */

/*     res1 = float64_muladd(SOFTFLOAT64(fa),SOFTFLOAT64(fb), SOFTFLOAT64(fc), 0); */
/*     res2 = float64_add(float64_mul(SOFTFLOAT64(fa),SOFTFLOAT64(fb)), SOFTFLOAT64(fc)); */

/*     printf("%f * %f + %f = %f (fused FMA) <-> %f (unfused FMA)  => %s\n", fa, fb, fc, DOUBLE(res1), DOUBLE(res2), res1==res2 ? "equal" : "not equal"); */


/*     if(res1 != res2) { */
/*       //printf("%f * %f + %f = %f (fused FMA) <-> %f (unfused FMA)  => Not Equal\n", fa, fb, fc, FLOAT(res1), FLOAT(res2)); */

/*       /\* char str1[20], str2[20]; *\/ */
/*       /\* sprintf(str1, "%f", FLOAT(res1)); *\/ */
/*       /\* sprintf(str2, "%f", FLOAT(res2)); *\/ */
/*       /\* if(strcmp(str1, str2)) *\/ */
/*       /\* 	{ *\/ */
/*       /\* 	  printf("%f * %f + %f = %f (fused FMA) <-> %f (unfused FMA)  => Not Equal\n", fa, fb, fc, FLOAT(res1), FLOAT(res2)); *\/ */
/*       /\* 	  printf("fa = %x, fb = %x, fc = %x\n", SOFTFLOAT32(fa), SOFTFLOAT32(fb), SOFTFLOAT32(fc)); *\/ */
/*       /\* 	} *\/ */
      
/*     } */
/*     /\* else *\/ */
/*     /\*   printf("equal\n"); *\/ */
    
/*   } */


}

